package org.sixtythousand.joker.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.util.AttributeKey;
import org.sixtythousand.joker.*;
import org.sixtythousand.joker.handler.Handler;
import org.sixtythousand.joker.handler.HandlerManager;
import org.sixtythousand.joker.util.AbstractLifeCycle;
import org.sixtythousand.joker.util.Callback;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * @author zhoulk
 * @date 2023/10/12 10:40
 * @desc
 */
public class NettyConnectionManager extends AbstractLifeCycle {

    private static final String JOKER_CONNECTION = "jokerConnetcion";

    /**
     * 活跃的连接
     */
    private final Deque<Connection> connections = new ArrayDeque<>(100);
    /**
     * 维护空闲连接对象，请求完成后，Connection对象不会销毁，会缓存起来后续重复使用
     */
    private final Deque<Connection> freeConnections = new ArrayDeque<>(100);
    private final ConnectionFactory connectionFactory;
    private final Connector connector;
    private final Handler handler;
    protected Executor executor = Executors.newFixedThreadPool(100);

    @Override
    public void doStart() {

    }

    public NettyConnectionManager(
            Connector connector,
            ConnectionFactory connectionFactory,
            Handler handler
    ) {
        this.connector = connector;
        this.connectionFactory = connectionFactory;
        this.handler = handler;
    }

    public void onAccept(ChannelHandlerContext ctx) {
        Connection connection = freeConnections.poll();
        if (connection == null) {
            JChannel channel = newChannel(ctx);
            connection = connectionFactory.newConnection(channel, handler, ctx.executor());
            channel.setConnection(connection);
            channel.addReadCallback(connection.newChannelCallback());
            AttributeKey<JChannel> connectionKey = AttributeKey.valueOf(JOKER_CONNECTION);
            ctx.channel().attr(connectionKey).set(channel);

            try {
                connections.offer(connection);
            } catch (Exception e) {
                // todo
            }
        }
    }

    public void onRead(ChannelHandlerContext ctx, FullHttpRequest msg) {
        AttributeKey<JChannel> connectionKey = AttributeKey.valueOf(JOKER_CONNECTION);
        ByteBuf content = msg.content();
        JChannel channel = ctx.channel().attr(connectionKey).get();
        if (channel == null) {
            onAccept(ctx);
            channel = ctx.channel().attr(connectionKey).get();
        }

        NettyHttpChannel httpChannel = (NettyHttpChannel) channel;
        NettyHttpRequest nettyHttpRequest = new NettyHttpRequest(httpChannel, msg);
        Callback callback = channel.readCallback();
        Runnable runnable = callback.asyncSucceeded(nettyHttpRequest);
        executor.execute(runnable);
    }

    private JChannel newChannel(ChannelHandlerContext ctx) {
        return new NettyHttpChannel(ctx);
    }


}
